package com.cskaoyan.javase.oop1._2reference;

/**
 * 我们第一次认识和了解引用数据类型是在数组这一章节
 * 我们通过JVM内存模型图和数组的初始化过程，知道：
 * 一个引用数据类型变量，分为两个部分：
 *      1.在栈上创建引用，它是一个局部变量。
 *      2.在堆上开辟空间，创建对象。
 * 栈上的引用通过存储堆上对象的地址和对象产生联系。
 * 对象是引用数据类型的实质，但我们只能通过栈上引用间接访问堆上对象。
 * 按照这样去理解引用数据类型,那么引用数据类型和基本数据类型基本就没有关系了
 * 这样割裂开两个概念是不好的.
 * 现在，我们已经学习过对象与类的知识点了，是时候进一步或者换一个角度去了解引用数据类型了。
 *
 * 先回顾一下，在Java基础语法部分，我们给出的数据类型的概念/定义：
 * 数据类型： 表示的是一组数据的集合，和基于该数据集合的一组合法操作。
 *
 * 这个定义套在基本数据类型上，实在再合适不过了。
 * 比如int类型，它的取值范围是固定的，有限的，能够做的操作（加减乘除等）也是被限制的。
 * 那么这个定义能不能套在引用数据类型中呢？能否用数据类型的概念来统一基本数据类型和引用数据类型呢？
 *
 * 接下来我们需要分析一下，这个问题。
 * 在上一节类的定义中，类中的成员包括：
 *      1.成员变量
 *      2.成员方法
 * 成员变量本质上就是数据，成员方法本质上就是操作，那么假设做以下类比：
 *      1.数据的集合： 类中成员变量的集合
 *      2.操作的集合： 类中成员方法的集合
 * 于是，就可以做出以下总结：
 *
 *      一个类的定义，实际上就是定义了一种全新的数据类型，一种自定义的数据类型。
 *      这种完全不同于基本数据类型的数据类型，我们称之为"引用数据类型"。
 *      注：当然引用数据类型不仅仅包括类，但大体上上述说法是没问题的。
 *
 *   总结: 数据类型 = 数据 + 操作
 *         定义一个类,成员变量的集合就是数据,成员方法的集合就是操作
 *         所以定义类,是定义了一个新的数据类型,就是引用数据类型
 *
 * 引用数据类型,和基本数据类型的不同点:
 * 当我们在程序中使用一个基本数据类型时
 * 由于基本数据类型是JVM当中已经预先定义好的（所以基本数据类型叫"内置数据类型"）
 * JVM可以清楚的知道这个基本数据类型变量在内存中的存储方式（占用空间大小、结构等等），JVM能够正常开辟空间，正常给变量初始化赋值。
 *
 * 但是类这种引用数据类型，并不是内置数据类型，而是我们自定义的数据类型。
 * 现在我们要根据一个类来创建它的对象
 * 要让JVM帮助我们开辟空间创建引用和对象，JVM怎么知道到底要创建什么呢？
 * 难道它未卜先知吗？
 *
 * 显然是不可能的，某个类在一开始并不被JVM"认识"
 *      ——它不知道类中有什么，这时JVM必然不可能对类做任何操作,包括创建对象。
 * 所以在对某个类做任何操作之前，都需要让JVM来"认识了解"这个类型。
 *
 * (重点)在Java中，把JVM"认识了解"一个类型的过程，称之为类加载。
 * 通过类加载,JVM认识和了解该类型(比如该类下存在什么成员,有哪些结构等等)
 * 这样JVM就能够完成该类的一些操作了(比如创建对象等)
 *
 * 类加载:
 * 关于类加载,详细的流程,具体的细节,会在后面有专门的章节学习,今天我们只了解最重要的点:
 * 首先,类加载是JVM通过I/O流的形式,将某个类的字节码文件(.class文件)读取进方法区,经过一系列的流程,从而完成类加载.
 *
 * IO流形式: 比如将U盘上的学习资料拷贝到电脑上 这个过程就是一个IO流的过程
 * IO的特点就是慢(和内存比)
 * 所以这就导致,进行类加载,往往效率很低
 * 那么出于程序的运行效率考虑,类加载必然是越少越好,所以类加载具有以下特点:
 * (重点) 类加载是懒加载,只有当出现迫不得已,必须要加载某个类时,JVM才会类加载它.
 * (重点)在Java中,我们把JVM迫不得已,必须要类加载某个类的场景,称之为"类加载的时机"
 *      当程序运行到"类加载的时机",JVM会先进行类加载,类加载之后,再完成该操作
 *
 * 思考:
 *  1.new创建某个类的对象,需不需要类加载?new对象是不是类加载的时机?
 *      必然是需要类加载该类的,所以new对象是典型的类加载时机
 *
 *  2.new对象是类加载时机,那么是先类加载,还是先创建对象?
 *      必然是先类加载
 *
 * 补充:
 *      1.目前,我们已经知道的类加载的时机:
 *          a.new对象
 *          b.启动main方法,启动某个类的main方法,会先类加载这个类.
 *          c.未完待续....
 *
 *
 *      2.思考:
 *          类加载的时机有很多,那么是不是碰到了一次类加载的时机,就会类加载该类一次呢?
 *          类加载对于某个类,有几次?
 *          (非常重要) 在一个Java程序的某次运行过程中,某个类的类加载最多只有一次
 *                  某个类在第一次碰到类加载的时机,就会类加载它
 *                  然后直到程序执行完毕,就不会再次类加载了!!
 *
 *      3.扩展/思考：
 *      JDK源码中的类，比如String，这些类还需要类加载吗？
 *      是需要的
 *      当然和程序员自定义类的类加载，JDK源码中的类的类加载还是有不同的：
 *      使用的类加载器不同！
 *
 * @since 17:29
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    // 在启动main方法之前,需要先类加载Demo,类加载完毕后,再启动main方法
    public static void main(String[] args) {
        System.out.println("hello world!");
        // new对象是类加载的时机,这里会触发Student类的类加载
        Student s = new Student();
        // 再次new对象,就不会再次触发Student类的类加载了.因为类加载只有一次
        Student s2 = new Student();

        /*
            这里会不会触发类加载?
            new对象确实是类加载的时机
            但是这里不会再次类加载了
            因为启动main方法已经触发了该类的类加载
            类加载只有一次!
         */
        Demo d = new Demo();
    }
}

class Student{}